struc RootDir
	.file_name: resd 2
	.file_ext: resb 3
	.attr: resb 1
	.reserved: resb 10
	.time: resw 1
    .date: resw 1
    .cluster: resw 1
    .file_len: resd 1
endStruc


; 获取磁盘类型
DiskType:
    mov ah, 0x15
    mov dl, 0
    int 0x13
    ret


; 函数声明ReadFile(high, low, filename)
; 将磁盘中的文件读到内容中
; @param [#1]          high 文件存放高位地址
; @param [#2]          low 文件存放低位地址
; @param [#3]          filename 文件名
; 将high * 0x10 + low
ReadFile:
    ; 读取根目录数据至 [es:bx] = 0x7e00
    mov ax, 0x7e0
    mov es, ax
    mov bx, 0
    push 19
    call GetData

    push word [esp + 6]
    call GetRootDirIdx
    mov dx, 32
    mul dx

    mov bx, 0
    add bx, ax

    ; 获取文件起始簇号
    call GetStartCluster

    ; 保存起始簇号
    mov dx, ax

    ; 读取FAT表数据至 [es:bx] = 0x7e00
    mov ax, 0x7e0
    mov es, ax
    mov bx, 0
    push 1
    call GetData

    mov ax, dx
    jmp sector

rf_increse:
    mov cx, word [esp + 2]
    add cx, 0x20
    mov word [esp + 2], cx
sector:
    mov cx, word [esp + 2]
    mov es, cx
    mov bx, word [esp + 4]
    mov ax, dx
    add ax, 33 - 2
    push ax
    call GetData
next:
    mov cx, 0x7e0
    mov es, cx
    mov bx, 0
    push dx
    call GetNextCluster
    mov dx, ax
    push ax
    call IsLastCluster
    test ax, ax
    jnz rf_increse

    call GetFileSize
    ret 6


; 读取扇区数据
; 将指定逻辑扇区的数据读到es:bx指示的内存缓冲区中
; @param [#1]       [in]    逻辑扇区
; @param es:bx      [in]    缓冲区
; @return 
GetData:
    ; mov ax, word [esp + 4]
    push dx
    push word [esp + 4]
    call LBACHS
    mov dl, 0           ; 驱动器号
    mov ah, 0x02        ; 中断功能号
    mov al, 1           ; 扇区数
    int 0x13
    pop dx
    ret 2


; LBA转CHS
; @param lba [in]   逻辑扇区
; [out]   ch = 柱面
; [out]   cl = 扇区
; [out]   dh = 磁头
LBACHS:
    push bx
    push ax
    mov ax, word [esp + 6]
    mov bl, 18
    div bl
    mov cl, ah
    inc cl
    xor ah, ah
    mov bl, 2
    div bl
    mov ch, al
    mov ax, word [esp + 6]
    mov bl, 18
    div bl
    xor ah, ah
    mov bl, 2
    div bl
    mov dh, ah
    pop ax
    pop bx
    ret 2


; 获取指定文件根目录位置
; @param [#1]               文件名称
; @param es:bx              根目录首地址
; @return ax
GetRootDirIdx:
    mov si, word [esp + 2]
    mov di, bx
    mov cx, 0
    jmp compare

progression:
    add si, 1
    add bx, 1
compare:
    mov al, byte [si]
    test al, al
    jz grdi_end
    cmp al, byte [es:bx]
    jz progression
grdi_false:
    add cx, 1
    add di, 32
    mov bx, di
    add si, word [esp + 2]
    jmp compare
grdi_end:
    mov ax, cx
    ret 2


; 获取文件名
; es:bx 根目录
GetFileName:
    ret


; 获取起始簇号
; @param    [in]    es:bx 根目录结构首地址
; @return ax
GetStartCluster:
    mov ax, word [es:bx + 26]
    ret


; 获取文件大小
; @param es:bx    [in]      根目录首地址
; @return eax               文件大小
GetFileSize:
    mov eax, dword [es:bx + 28]
    ret


; 获取下个簇号
; @param [#1]       [in]        当前簇号
; @return ax        [out]       下一簇号
GetNextCluster:
    push dx
    push bx
    push cx

    mov ax, [esp + 8]
    mov cl, 3
    mul cl
    mov cl, 2
    div cl
    test ah, ah
    jz even
    xor ah, ah
    add bx, ax
    mov dx, word [es:bx]
    shr dx, 4
    jmp end
even:
    add bx, ax
    mov dx, word [es:bx]
    and dx, 0x0fff
end:
    mov ax, dx
    pop cx
    pop bx
    pop dx
    ret 2


; 是否最后一簇
; @param [#1]     [in]        当前簇号
; @return 0     false
;         非0   true
IsLastCluster:
    mov ax, word [esp + 2]
    test ax, 0xff8
    jz true
    test ax, 0xff9
    jz true
    test ax, 0xffa
    jz true
    test ax, 0xffb
    jz true
    test ax, 0xffc
    jz true
    test ax, 0xffd
    jz true
    test ax, 0xffe
    jz true
    test ax, 0xfff
    jz true
false:
    xor ax, ax
    ret 2
true:
    mov ax, 1
    ret 2